package com.tcoiss.webservice.service.impl;

import com.alibaba.fastjson.JSON;
import com.tcoiss.common.core.domain.R;
import com.tcoiss.common.core.enums.ErroEnums;
import com.tcoiss.common.core.exception.CustomException;
import com.tcoiss.common.core.utils.DateUtils;
import com.tcoiss.common.core.utils.StringUtils;
import com.tcoiss.webservice.domain.invoice.*;
import com.tcoiss.webservice.service.IApiService;
import com.tcoiss.webservice.service.IInvoiceService;
import com.tcoiss.webservice.utils.AesUtils;
import com.tcoiss.webservice.utils.Base64Utils;
import com.tcoiss.webservice.utils.SignatureUtil;
import org.json.JSONObject;
import org.json.XML;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class InvoiceServiceImpl implements IInvoiceService {

    @Autowired
    private IApiService iApiService;

    /**
     * 开具接口
     *
     * @param vo
     * @return
     */
    @Override
    public R issueInvoice(RecordCommonVo vo) {
        // 调用开票API获取响应报文
        Map<String, RecordCommonVo> root = new HashMap<>();
        List<RefpVo> refps = new ArrayList<>();
        root.put("data", vo);
        Map<String, Object> result = iApiService.executeByApiCode("issueInvoice", root);
        //解析报文
        Map<String, Object> body = (Map<String, Object>) result.get("Body");
        Map<String, Object> issueInvoiceResponse = (Map<String, Object>) body.get("issueInvoiceResponse");
        String out = issueInvoiceResponse.get("out").toString();
        List<Map<String, Object>> data = getReturn(out);
        for (int i = 0; i < data.size(); i++) {
            Map<String, Object> obj = data.get(i);
            RefpVo refpVo = new RefpVo();
            SaleInvoiceVo fpseq = JSON.parseObject(JSON.toJSONString(vo.getRecords().get(i)), SaleInvoiceVo.class);
            refpVo.setFpseq(fpseq.getFpseq());
            refpVo.setRetcode(obj.get("RETCODE").toString());
            refpVo.setRetmsg(obj.get("RETMSG").toString());
            if (obj.get("RETCODE").toString().equals("4011")) {
                refpVo.setJe(obj.get("JE").toString());
                refpVo.setSe(obj.get("SE").toString());
                refpVo.setKprq(obj.get("KPRQ").toString());
                refpVo.setFpdm(obj.get("FPDM").toString());
                refpVo.setFphm(obj.get("FPHM").toString());
            }
            refps.add(refpVo);
        }
        vo.setRefps(refps);
        return R.ok(vo);
    }

    /**
     * 电子发票开具接口
     *
     * @param vo
     * @return
     */
    @Override
    public R dzIssueInvoice(RecordCommonVo vo) {
        // 调用电子开票API获取响应报文
        Map<String, String> root = new HashMap<>();
        root.put("nsrsbh", vo.getNsrsbh());
        root.put("timestamp", String.valueOf(java.lang.System.currentTimeMillis() / 1000));
        try {
            DzInvoiceHeaderVo headerVo = JSON.parseObject(JSON.toJSONString(vo.getRecords().get(0)), DzInvoiceHeaderVo.class);
            // 生成单个发票数据
            String data = JSON.toJSONString(headerVo);
            // 生成AES加密密钥
            String aesKey = genKey(root);
            // AES加密 加密Data数据
            String aesString = null;
            aesString = AesUtils.Encrypt(data, aesKey);
            String key = vo.getNsrsbh();
            root.put("data", aesString);
            // 生成签名 将时间戳、数据密文、纳税人识别号
            String sign = SignatureUtil.generateSignature(root, key, SignatureUtil.SignType.HMACSHA256);
            root.put("signture", sign);
            Map<String, Object> resultMap = iApiService.executeByApiCode("DzIssueInvoice", root);
            List<RefpVo> refpVoList = new ArrayList<>();
            RefpVo ref = new RefpVo();
            ref.setFpseq(headerVo.getFpseq());
            ref.setRetcode(resultMap.get("status").toString());
            ref.setRetmsg(resultMap.get("message").toString());
            if ("0000".equals(resultMap.get("status").toString())) {
                ref.setDzseq(resultMap.get("fpqqlsh").toString());
            }
            refpVoList.add(ref);
            vo.setRefps(refpVoList);
            return R.ok(vo);
        } catch (Exception e) {
            throw new CustomException(ErroEnums.APIERRO.getCode(), ErroEnums.APIERRO.getInfo() + e.getMessage(), e);
        }
    }

    /**
     * 电子发票查询接口
     *
     * @param vo
     * @return
     */
    @Override
    public R dzQueryInvoice(RecordCommonVo vo) {
        // 调用电子开票API获取响应报文
        Map<String, String> root = new HashMap<>();
        root.put("nsrsbh", vo.getNsrsbh());
        root.put("timestamp", String.valueOf(java.lang.System.currentTimeMillis() / 1000));
        try {
            String[] headerVo = vo.getFpqqlsh();
            // 组装DataJSON串
            Map<String, String> dataMap = new HashMap<>();
            dataMap.put("fpqqlsh",Arrays.toString(headerVo));
            dataMap.put("isOfferInvoiceDetail", "true");
            String data = JSON.toJSONString(dataMap);
            // 生成AES加密密钥
            String aesKey = genKey(root);
            // AES加密 加密Data数据
            String aesString = AesUtils.Encrypt(data, aesKey);
            // 生成最终映射Map
            Map<String, String> requestMap = new HashMap<>();
            String key = vo.getNsrsbh();
            requestMap.put("timestamp", (String) root.get("timestamp"));
            requestMap.put("nsrsbh", key);
            requestMap.put("data", aesString);
            // 生成签名 将时间戳、数据密文、纳税人识别号
            String sign = SignatureUtil.generateSignature(requestMap, key, SignatureUtil.SignType.HMACSHA256);
            requestMap.put("signture",sign);
            Map<String, Object> resultMap = iApiService.executeByApiCode("DzqueryInvoice", requestMap);
            String result = (String) resultMap.get("result");
            List<RefpVo> refps = new  ArrayList<>();
            if(result.equals("success")){
                List<Map<String,Object>> list = (List<Map<String, Object>>) resultMap.get("list");
                for (Map<String,Object> map:list){
                    RefpVo ref = new RefpVo();
                    ref.setDzseq(map.get("c_fpqqlsh").toString());
                    ref.setUrl(map.get("c_url").toString());
                    ref.setJe(map.get("c_bhsje").toString());
                    ref.setSe(map.get("c_hjje").toString());
                    ref.setKprq(map.get("c_kprq").toString());
                    ref.setFpdm(map.get("c_fpdm").toString());
                    ref.setFphm(map.get("c_fphm").toString());
                    ref.setJpgurl(map.get("c_imgUrls").toString());
                    ref.setRetmsg(map.get("c_msg").toString() + map.get("c_resultmsg"));
                    ref.setRetcode(map.get("c_status").toString());
                    refps.add(ref);
                }
            }else {
                RefpVo ref = new RefpVo();
                ref.setRetcode(result);
                ref.setRetmsg(resultMap.get("errorMsg").toString());
                refps.add(ref);
            }
            vo.setRefps(refps);
            return R.ok(vo);
        } catch (Exception e) {
            throw new CustomException(ErroEnums.APIERRO.getCode(), ErroEnums.APIERRO.getInfo() + e.getMessage(), e);
        }
    }

    /**
     * 电子发票红票申请接口
     * @param vo
     * @return
     */
    @Override
    public R dzRedInvoice(RecordCommonVo vo) {
        // 调用电子开票API获取响应报文
        Map<String, String> root = new HashMap<>();
        root.put("nsrsbh", vo.getNsrsbh());
        root.put("timestamp", String.valueOf(java.lang.System.currentTimeMillis() / 1000));
        try {
            DzRedInvoice redVo = JSON.parseObject(JSON.toJSONString(vo.getRecords().get(0)), DzRedInvoice.class);
            // 组装DataJSON串
            String data = JSON.toJSONString(redVo);
            // 生成AES加密密钥
            String aesKey = genKey(root);
            // AES加密 加密Data数据
            String aesString = AesUtils.Encrypt(data, aesKey);
            String key = vo.getNsrsbh();
            root.put("data", aesString);
            // 生成签名 将时间戳、数据密文、纳税人识别号
            String sign = SignatureUtil.generateSignature(root, key, SignatureUtil.SignType.HMACSHA256);
            root.put("signture",sign);
            Map<String, Object> resultMap = iApiService.executeByApiCode("DzRedInvoice", root);
            // 拼装返回数据
            List<RefpVo> refps = new  ArrayList<>();
            RefpVo ref = new RefpVo();
            ref.setFpseq(redVo.getFpseq());
            if(resultMap != null && resultMap.size() > 0){
                ref.setRetcode(resultMap.get("status").toString());
                ref.setRetmsg(resultMap.get("message").toString());
            }
            refps.add(ref);
            vo.setRefps(refps);
            return R.ok(vo);
        } catch (Exception e) {
            throw new CustomException(ErroEnums.APIERRO.getCode(), ErroEnums.APIERRO.getInfo() + e.getMessage(), e);
        }
    }

    /**
     * 电子发票红票查询接口
     *
     * @param vo
     * @return
     */
    @Override
    public R dzRedQueryInvoice(RecordCommonVo vo) {
        // 调用电子开票API获取响应报文
        Map<String, String> root = new HashMap<>();
        root.put("nsrsbh", vo.getNsrsbh());
        root.put("timestamp", String.valueOf(java.lang.System.currentTimeMillis() / 1000));
        try {
            Object  redVo= vo.getRecords().get(0);
            // 组装DataJSON串
            String data = JSON.toJSONString(redVo);
            // 生成AES加密密钥
            String aesKey = genKey(root);
            // AES加密 加密Data数据
            String aesString = AesUtils.Encrypt(data, aesKey);
            // 生成最终映射Map
            String key = vo.getNsrsbh();
            root.put("data", aesString);
            // 生成签名 将时间戳、数据密文、纳税人识别号
            String sign = SignatureUtil.generateSignature(root, key, SignatureUtil.SignType.HMACSHA256);
            root.put("signture",sign);
            Map<String, Object> resultMap = iApiService.executeByApiCode("DzRedQueryInvoice", root);
            return R.ok(resultMap);
        } catch (Exception e) {
            throw new CustomException(ErroEnums.APIERRO.getCode(), ErroEnums.APIERRO.getInfo() + e.getMessage(), e);
        }
    }

    /**
     * 开具测试接口
     *
     * @param vo
     * @return
     */
    @Override
    public R issueInvoiceTest(RecordCommonVo vo) {
        List<Object> records = vo.getRecords();
        List<RefpVo> refps = new ArrayList<>();
        for (Object obj : records) {
            Map<String, Object> objMap = (Map<String, Object>) obj;
            SaleInvoiceVo saleInvoiceVo = JSON.parseObject(JSON.toJSONString(objMap), SaleInvoiceVo.class);
            RefpVo refpVo = new RefpVo();
            refpVo.setFpseq(saleInvoiceVo.getFpseq());
            refpVo.setRetcode("4011");
            refpVo.setRetmsg("4011-开票成功 [0000,]");
            refpVo.setJe("3000");
            refpVo.setSe("130");
            refpVo.setKprq(DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD));
            refpVo.setFpdm(getFixLenthString(12));
            refpVo.setFphm(getFixLenthString(8));
            refps.add(refpVo);
        }
        vo.setRefps(refps);
        return R.ok(vo);
    }

    /**
     * 打印接口
     * @param vo
     * @return
     */
    @Override
    public R printInvoice(RecordCommonVo vo) {
        // 调用开票API获取响应报文
        Map<String, RecordCommonVo> root = new HashMap<>();
        List<RefpVo> refps = new ArrayList<>();
        root.put("data", vo);
        Map<String, Object> result = iApiService.executeByApiCode("printInvoice", root);
        //解析报文
        Map<String, Object> body = (Map<String, Object>) result.get("Body");
        Map<String, Object> issueInvoiceResponse = (Map<String, Object>) body.get("printInvoiceResponse");
        String out = issueInvoiceResponse.get("out").toString();
        List<Map<String, Object>> data = getReturn(out);
        for (Map<String, Object> obj : data) {
            RefpVo refpVo = new RefpVo();
            refpVo.setRetcode(obj.get("RETCODE").toString());
            refpVo.setRetmsg(obj.get("RETMSG").toString());
            if (obj.get("RETCODE").toString().equals("5011")) {
                refpVo.setFpzl(obj.get("FPZL").toString());
                refpVo.setFpdm(obj.get("FPDM").toString());
                refpVo.setFphm(obj.get("FPHM").toString());
            }
            refps.add(refpVo);
        }
        vo.setRefps(refps);
        return R.ok(vo);
    }

    /**
     * 打印测试接口
     *
     * @param vo
     * @return
     */
    @Override
    public R printInvoiceTest(RecordCommonVo vo) {
        List<RefpVo> refps = new ArrayList<>();
        /*********************************** 测试模拟 *******************************************/
        List<Object> records = vo.getRecords();
        for (Object obj : records) {
            Map<String, Object> objMap = (Map<String, Object>) obj;
            PrintInvoiceVo printInvoiceVo = JSON.parseObject(JSON.toJSONString(objMap), PrintInvoiceVo.class);
            RefpVo refpVo = new RefpVo();
            refpVo.setRetcode("5011");
            refpVo.setRetmsg("打印成功");
            refpVo.setFpzl(printInvoiceVo.getFpzl());
            refpVo.setFpdm(printInvoiceVo.getFpdm());
            refpVo.setFphm(printInvoiceVo.getFphm());
            refps.add(refpVo);
        }
        vo.setRefps(refps);
        return R.ok(vo);
    }

    /**
     * 作废接口
     *
     * @param vo
     * @return
     */
    @Override
    public R invalidInvoice(RecordCommonVo vo) {
        // 调用开票API获取响应报文
        Map<String, RecordCommonVo> root = new HashMap<>();
        List<RefpVo> refps = new ArrayList<>();
        root.put("data", vo);
        Map<String, Object> result = iApiService.executeByApiCode("invalidInvoice", root);
        //解析报文
        Map<String, Object> body = (Map<String, Object>) result.get("Body");
        Map<String, Object> issueInvoiceResponse = (Map<String, Object>) body.get("invalidInvoiceResponse");
        String out = issueInvoiceResponse.get("out").toString();
        List<Map<String, Object>> data = getReturn(out);
        int i = 0;
        for (Map<String, Object> obj : data) {
            RefpVo refpVo = new RefpVo();
            InvalidInvoice fpseq = JSON.parseObject(JSON.toJSONString(vo.getRecords().get(i++)), InvalidInvoice.class);
            refpVo.setFpseq(fpseq.getSeq());
            refpVo.setRetcode(obj.get("RETCODE").toString());
            refpVo.setRetmsg(obj.get("RETMSG").toString());
            if (obj.get("RETCODE").toString().equals("6011")) {
                refpVo.setFpzl(obj.get("FPZL").toString());
                refpVo.setFpdm(obj.get("FPDM").toString());
                refpVo.setFphm(obj.get("FPHM").toString());
            }
            refps.add(refpVo);
        }
        vo.setRefps(refps);
        return R.ok(vo);
    }

    /**
     * 作废测试接口
     *
     * @param vo
     * @return
     */
    @Override
    public R invalidInvoiceTest(RecordCommonVo vo) {
        List<RefpVo> refps = new ArrayList<>();
        List<Object> records = vo.getRecords();
        for (Object obj : records) {
            Map<String, Object> invalidInvoice = (Map<String, Object>) obj;
            RefpVo refpVo = new RefpVo();
            refpVo.setRetcode("6011");
            refpVo.setRetmsg("作废成功");
            refpVo.setFpseq((String) invalidInvoice.get("seq"));
            refpVo.setFpzl((String) invalidInvoice.get("fpzl"));
            refpVo.setFphm((String) invalidInvoice.get("fphm"));
            refpVo.setFpdm((String) invalidInvoice.get("fpdm"));
            refps.add(refpVo);
        }
        vo.setRefps(refps);
        return R.ok(vo);
    }

    private List<Map<String, Object>> getReturn(String out) {
        List<Map<String, Object>> mapList = new ArrayList<>();
        if (StringUtils.isNotEmpty(out)) {
            // 返回参数解密
            String response = Base64Utils.decode(out);
            JSONObject xmlJSONObj = XML.toJSONObject(response);
            Map serviceJson = com.alibaba.fastjson.JSONObject.parseObject(xmlJSONObj.get("service").toString(), Map.class);
            Map errJson = (Map) serviceJson.get("err");
            int count = Integer.valueOf(errJson.get("count").toString());
            if (count == 1) {
                Map<String, Object> refp = (Map<String, Object>) errJson.get("refp");
                mapList.add(refp);
            } else {
                List<Map<String, Object>> refps = (List<Map<String, Object>>) errJson.get("refp");
                mapList.addAll(refps);
            }
        }
        return mapList;
    }

    /**
     * 根据提供长度,生成指定长度随机数
     *
     * @param strLength
     * @return
     */
    private String getFixLenthString(int strLength) {
        Random rm = new Random();
        // 获得随机数
        double pross = (1 + rm.nextDouble()) * Math.pow(10, ++strLength);
        // 将获得的获得随机数转化为字符串
        String fixLenthString = String.valueOf(pross);
        // 返回固定的长度的随机数
        return fixLenthString.substring(2, strLength + 1);
    }


    /**
     * 生成AES加密Key
     *
     * @param map
     * @return
     */
    private String genKey(Map<String, String> map) {
        String nsrsbh = map.get("nsrsbh");
        String timestamp = map.get("timestamp");
        String nsr = nsrsbh.substring(nsrsbh.length() - 6, nsrsbh.length());
        return nsr + timestamp;
    }
}
